#ifndef SCRIPTLOGIC_H_
#define SCRIPTLOGIC_H_

#include "AbstractLogic.h"
#include "NonCopyable.h"

#include "KeyboardEvent.h"
#include "Vector2.h"
#include <string>

class string;

namespace EntitySystem
{

class ScriptLogic : public AbstractLogic, public NonCopyable
{
public:

    ScriptLogic()
    {

    }

    virtual ~ScriptLogic()
    {

    }

    /**
     * Clones the concrete script logic.
     */

    virtual ScriptLogic* Clone() = 0;


    /**
     * Executes the Initialize function from script.
     */

    virtual void ExecuteInitialize() = 0;


    /**
     * Executes the Update function from script.
     */

    virtual void ExecuteUpdate() = 0;


    /**
     * Executes the OnTileCollision function from script.
     */

    virtual void ExecuteOnTileCollision(std::string* tile, Math::Vector2F& contactNormal) = 0;


    /**
     * Executes the OnEntityCollision function from script.
     */

    virtual void ExecuteOnEntityCollision(Entity* collided, Math::Vector2F& contactNormal) = 0;


    /**
     * Executes the OnKeyButtonDown function from script.
     */

    virtual void ExecuteOnKeyButtonDown(Key key, KeyMod mod, std::string& association) = 0;


    /**
     * Executes the OnKeyButtonUp function from script.
     */

    virtual void ExecuteOnKeyButtonUp(Key key, KeyMod mod, std::string& association) = 0;


    /**
     * Executes the OnDeath function from script.
     */

    virtual void ExecuteOnDeath() = 0;


    virtual const char* GetName() = 0;
};

namespace ScriptPredicates
{

struct ScriptExecutor
{
    virtual void operator()(ScriptLogic* script) = 0;
};

struct ScriptExecutorOnTileC : public ScriptExecutor
{

    virtual void operator()(ScriptLogic* script)
    {
        script->ExecuteOnTileCollision(tile, cNormal);
    }

    std::string* tile;
    Math::Vector2F cNormal;
};

struct ScriptExecutorOnEntityC : public ScriptExecutor
{

    virtual void operator()(ScriptLogic* script)
    {
        script->ExecuteOnEntityCollision(entity, cNormal);
    }

    Entity* entity;
    Math::Vector2F cNormal;
};

struct ScriptExecutorOnInit : public ScriptExecutor
{

    virtual void operator()(ScriptLogic* script)
    {
        script->ExecuteInitialize();
    }

};

struct ScriptExecutorOnDeath : public ScriptExecutor
{

    virtual void operator()(ScriptLogic* script)
    {
        script->ExecuteOnDeath();
    }

};

struct ScriptExecutorOnUpdate : public ScriptExecutor
{

    virtual void operator()(ScriptLogic* script)
    {
        script->ExecuteUpdate();
    }

};

struct ScriptExecutorOnKeyUp : public ScriptExecutor
{

    ScriptExecutorOnKeyUp(const KeyboardEvent &event, std::string& association) : assoc(association)
    {
        key = event.GetKey();
        mod = event.GetModifiers();
    }

    virtual void operator()(ScriptLogic * script)
    {
        script->ExecuteOnKeyButtonUp(key, mod, assoc);
    }

    Key key;
    KeyMod mod;
    std::string assoc;
};

struct ScriptExecutorOnKeyDown : public ScriptExecutor
{

    ScriptExecutorOnKeyDown(const KeyboardEvent &event, std::string & association) : assoc(association)
    {
        key = event.GetKey();
        mod = event.GetModifiers();
    }

    virtual void operator()(ScriptLogic * script)
    {
        script->ExecuteOnKeyButtonDown(key, mod, assoc);
    }

    Key key;
    KeyMod mod;
    std::string assoc;
};

};

}

#endif